#include "at24cxx.h"
#include "i2c_soft.h"
#include <rtdevice.h>

/**
 * @desc  : IIC器件多字节写函数 对于跨页写有特殊要求的需要再次封装一下
 * @param : addr 写入地址起始位置
 *          data 待写入数据首地址
 *          len 待写入数据字节个数
 * @return: RT_EOK/RT_ERROR
 */
rt_err_t eeprom_write(rt_uint16_t addr, rt_uint8_t *data, rt_uint16_t len)
{
    struct rt_i2c_msg msg[2];
    rt_uint8_t write_pos;

    write_pos = (rt_uint8_t)addr;

    msg[0].addr = EEPROM_SLAVE_ADDR;
    msg[0].flags = RT_I2C_WR;
    msg[0].len = 1;
    msg[0].buf = &write_pos;

    msg[1].addr = EEPROM_SLAVE_ADDR;
    msg[1].flags = RT_I2C_NO_START;
    msg[1].len = len;
    msg[1].buf = data;

    if (2 != rt_i2c_transfer(&i2c1_bus, &msg[0], 2))
    {
        rt_kprintf("i2c write data failed\r\n");
        return RT_ERROR;
    }
    else{
        return RT_EOK;
    }
}

/**
 * @desc  : eeprom器件多字节写入函数 针对跨页写数据进行处理
 * @param : WriteAddr 数据写入起始地址
 *          pBuffer 待写入数据首地址
 *          NumByteToWrite 待写入数据字节个数
 * @return: none
 */
void eeprom_buffer_write(rt_uint16_t WriteAddr, rt_uint8_t *pBuffer, rt_uint16_t NumByteToWrite)
{
    rt_uint8_t NumOfPage = 0, NumOfSingle = 0, count = 0;
    rt_uint16_t Addr = 0;

    Addr = WriteAddr % EEPROM_PAGE_SIZE;
    count = EEPROM_PAGE_SIZE - Addr;
    NumOfPage =  NumByteToWrite / EEPROM_PAGE_SIZE;
    NumOfSingle = NumByteToWrite % EEPROM_PAGE_SIZE;

    /* If WriteAddr is EEPROM_PAGE_SIZE aligned  */
    if (Addr == 0)
    {
        /* If NumByteToWrite < EEPROM_PAGE_SIZE */
        if (NumOfPage == 0)
        {
            eeprom_write(WriteAddr, pBuffer, NumOfSingle);
        }
        /* If NumByteToWrite > EEPROM_PAGE_SIZE */
        else
        {
            while (NumOfPage)
            {
                eeprom_write(WriteAddr, pBuffer, EEPROM_PAGE_SIZE);

                WriteAddr +=  EEPROM_PAGE_SIZE;
                pBuffer += EEPROM_PAGE_SIZE;
                NumOfPage--;
            }

            if (NumOfSingle != 0)
            {
                eeprom_write(WriteAddr, pBuffer, NumOfSingle);
            }
        }
    }
    /* If WriteAddr is not EEPROM_PAGE_SIZE aligned  */
    else
    {
        /* If NumByteToWrite < EEPROM_PAGE_SIZE */
        if (NumOfPage == 0)
        {
            /* If the number of data to be written is more than the remaining space

            in the current page: */
            if (NumByteToWrite > count)
            {
                /* Write the data conained in same page */
                eeprom_write(WriteAddr, pBuffer, count);

                /* Write the remaining data in the following page */
                eeprom_write((WriteAddr + count), (rt_uint8_t *)(pBuffer + count), (NumByteToWrite - count));
            }
            else
            {
                eeprom_write(WriteAddr, pBuffer, NumOfSingle);
            }
        }
        /* If NumByteToWrite > EEPROM_PAGE_SIZE */
        else
        {
            NumByteToWrite -= count;
            NumOfPage =  NumByteToWrite / EEPROM_PAGE_SIZE;
            NumOfSingle = NumByteToWrite % EEPROM_PAGE_SIZE;

            if (count != 0)
            {
                eeprom_write(WriteAddr, pBuffer, count);

                WriteAddr += count;
                pBuffer += count;
            }

            while (NumOfPage)
            {
                eeprom_write(WriteAddr, pBuffer, EEPROM_PAGE_SIZE);

                WriteAddr +=  EEPROM_PAGE_SIZE;
                pBuffer += EEPROM_PAGE_SIZE;
                NumOfPage--;
            }
            if (NumOfSingle != 0)
            {
                eeprom_write(WriteAddr, pBuffer, NumOfSingle);
            }
        }
    }
}

/**
 * @desc  : IIC器件读函数
 * @param : addr 待读数据地址起始位置
 *          data 待读取数据首地址
 *          len 待读取数据字节个数
 * @return: RT_EOK/RT_ERROR
 */
rt_err_t eeprom_read(rt_uint16_t addr, rt_uint8_t *data, rt_uint16_t len)
{
    struct rt_i2c_msg msg[2];
    rt_uint8_t read_pos;

    read_pos = (rt_uint8_t)addr;

    msg[0].addr = EEPROM_SLAVE_ADDR;
    msg[0].flags = RT_I2C_WR;
    msg[0].len = 1;
    msg[0].buf = &read_pos;

    msg[1].addr = EEPROM_SLAVE_ADDR;
    msg[1].flags = RT_I2C_RD;
    msg[1].len = len;
    msg[1].buf = data;

    if (2 != rt_i2c_transfer(&i2c1_bus, &msg[0], 2))
    {
        rt_kprintf("i2c read data failed\r\n");
        return RT_ERROR;
    }
    else{
        return RT_EOK;
    }
}


#ifdef RT_USING_FINSH
#include <finsh.h>
#include <rtdevice.h>

void ee_read(rt_uint16_t pos, rt_uint16_t len)
{
    rt_uint8_t read_buff[100] = {0};
    rt_uint16_t i = 0;

    eeprom_read(pos, read_buff, len);
    for (i = 0; i < len ; i++)
        rt_kprintf("%d \r\n", read_buff[i]);
}

void ee_write(rt_uint16_t pos, rt_uint16_t len)
{
    rt_uint8_t write_buff[100] = {0};
    rt_uint16_t i = 0;

    for (i = 0; i < len ; i++)
        write_buff[i] = i;

    eeprom_buffer_write(pos, write_buff, len);
}

FINSH_FUNCTION_EXPORT(ee_read, ee_read. e.g: ee_read(1, 5))
FINSH_FUNCTION_EXPORT(ee_write, ee_write. e.g: ee_write(1, 5))

#endif
